package com.sjx.onelinecord.test

import java.lang.StringBuilder

fun main() {
    var study: Study? = null
    var studyOne = Study("sjx", 22)
    var studyTwo = Study("xin", 23)
    study?.readBooks()
    study?.doHomeWorks()
    studyOne?.readBooks()
    studyOne?.doHomeWorks()
    /*
       let既不是操作符，也不是什么关键字，而是一个函数，let函数会将原始调用对象
       study/studyOne/studyTwo对象本身作为参数传递到Lambda表达式中，当Lamb
       da表达式的参数只有一个时，可以不用声明参数名直接使用it关键字代替即可。具体
       let函数的用法查看《第一行代码》2.8节77页。
     */
    studyTwo?.let {
        it.readBooks()
        it.doHomeWorks()
    }

    /**
     * -- 标准函数with
     * with函数接收两个参数：第一个参数可以是一个任意类型的对象，第二个参数是一个
     * Lambda表达式。with函数会在Lambda表达式中提供第一个参数对像的上下文，并使
     * 用Lambda表达式中的最后一行代码作为返回值返回。
     *
     * 下面的举例：
     * 首先我们给with函数的第一个参数传入了一个StringBuilder对象，那么接下来整个
     * Lambda表达式的上下文就会是这个StringBuilder对象。Lambda表达式的最后一行
     * 代码会作为with函数的返回值返回，将返回值赋予result，最终我们将结果打印出来。
     */
    val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape")
    val result = with(StringBuilder()) {
        append("Start eating fruits.\n")
        for (fruits in list) {
            append(fruits + "\n")
        }
        append("Ate all fruits.\n")
        toString()
    }

    println(result)

    /**
     *  -- 标准函数run
     *  run函数的用法和使用场景其实和with函数是非常类似的，只是稍微做了一些
     *  语法改动而已。首先run函数通常不会直接调用，而是要在某个对象的基础上调
     *  用；其次run函数只接收一个Lambda函数，并且会在Lambda表达式中提供调用
     *  对象的上下文。其他方面和with函数是一样的，包括也会用Lambda表达式中的
     *  最后一行作为返回值返回。
     */
    val resultOne = StringBuilder().run {
        append("Start eating fruits.\n")
        for (fruits in list) {
            append(fruits + "\n")
        }
        append("Ate all fruits.\n")
        toString()
    }

    println(resultOne)

    /**
     *  -- 标准函数apply(推荐指数一颗星）
     *  apply函数和run函数也是极其类似的，都要在某个对象上调用，并且只接收一个Lambda参数
     *  ，也会在Lambda表达式中提供调用对象的上下文，但是apply函数无法指定返回值，而是会自
     *  动返回调用对象本身，然后把调用对象本身赋值给例子中的resultTwo
     */
    val resultTwo = StringBuilder().apply {
        append("Start eating fruits.\n")
        for (fruits in list) {
            append(fruits + "\n")
        }
        append("Ate all fruits.\n")
    }

    println(resultTwo.toString())

    //{ status }？ 使用了判断，若status为true才执行run方法,run也可以换成apply let 等
    //{ status }? 也可以使用study.xx,反正花括号里面是一个属性值的判断处理，若是为true
    //则takeIf的值不为空，因为加了？判空处理，takeIf值不为空则可以执行run方法。
    val status = true
    studyOne.takeIf { status }?.run {
        readBooks()
    }
}

class Study(var name: String, var age: Int) {

    fun readBooks(): String  {
        println("${name}看作业")
        return "manon"
    }

    fun doHomeWorks() {
        println("${name}写作业")
    }

}